// checksum.cpp: implementation of the checksum class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "checksum.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

// A Checksum Algorithm by Joseph M. Newcomer
// Ref: "http://www.pgh.net/~newcomer/checksum.htm"

// Note the use of overloading to get various data types. To use the checksum algorithm,
// create a variable of type checksum, for example, in your desired data structure.
// You can then call the various add methods to add in the values you wish to checksum
// (it is rarely the case that doing a checksum of the bytes of the structure yields anything useful;
// for example, some might represent transient computations that do not affect the actual values of importance;
// and checksumming the bytes would mean that you checksum the pointers to strings, not the contents of the strings,
// which leads to the situation where two strings that are otherwise identical would produce different checksums
// because they were at different addresses. So at some point you determine the structure contains all the values you care about
// (for example, just after you've read the document, or initialized all the values in OnInitDialog),
// and you apply the following operations to your checksum variable (which I'll call original).
// It is convenient to package up the checksum algorithm as shown.
//
//  void CMyClass::doChecksum(checksum & chk) const
//  {
//      chk.clear();
//      chk.add(flag); // a BOOL
//      chk.add(text); // a CString
//      chk.add(size); // a DWORD
//  }
//
// so you call it as doChecksum(original);Now, at some point, you determine that you have changed something;
// for example, the user has clicked a checkbox. You capture the Boolean value of the checkbox to the flag variable,
// then call doChecksum with a new variable, for example, by having the button-clicked, edit-changed, etc.
// handler call a function computeModification
//
//  void CMyClass::computeModification()
//  {
//      checksum current;
//      current.clear();
//      doChecksum(current);
//      CMyClass::SetModified(current.get() != original.get());
//  }
//
// Note that if the checkbox was originally unchecked, and the user checks it, we get an indication
// (at least in the Modified flag) that the document has changed. If the user then unchecks it,
// and all other values have been unchanged, we get an indication that the content has not been modified
// (this means the checksum has to account for all forms of change! And that's your responsibility!)
//
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////


/****************************************************************************
*                                  checksum::add
* Inputs:
*        DWORD d: word to add
* Result: void
* 
* Effect: 
*        Adds the bytes of the DWORD to the checksum
****************************************************************************/

void checksum::add(DWORD value)
{
 union { DWORD value; BYTE bytes[4]; } data;
 data.value = value;
 for(UINT i = 0; i < sizeof(data.bytes); i++)
    add(data.bytes[i]);
} // checksum::add(DWORD)

/****************************************************************************
*                                 checksum::add
* Inputs:
*        WORD value:
* Result: void
* 
* Effect: 
*        Adds the bytes of the WORD value to the checksum
****************************************************************************/

void checksum::add(WORD value)
{
 union { DWORD value; BYTE bytes[2]; } data;
 data.value = value;
 for(UINT i = 0; i < sizeof(data.bytes); i++)
   add(data.bytes[i]);
} // checksum::add(WORD)

/****************************************************************************
*                                 checksum::add
* Inputs:
*        BYTE value:
* Result: void
* 
* Effect: 
*        Adds the byte to the checksum
****************************************************************************/

void checksum::add(BYTE value)
{
 BYTE cipher = (BYTE)((WORD)value ^ (r >> 8));
 r = (WORD)((cipher + r) * c1 + c2);
 sum += cipher;
} // checksum::add(BYTE)

/****************************************************************************
*                                 checksum::add
* Inputs:
*        const CString & s: String to add
* Result: void
* 
* Effect: 
*        Adds each character of the string to the checksum
****************************************************************************/

void checksum::add(const CString & s)
{
 for(int i = 0; i < s.GetLength(); i++)
    add((BYTE)s.GetAt(i));
} // checksum::add(CString)

/****************************************************************************
*                                 checksum::add
* Inputs:
*        LPBYTE b: pointer to byte array
*        UINT length: count
* Result: void
* 
* Effect: 
*        Adds the bytes to the checksum
****************************************************************************/

void checksum::add(LPBYTE b, UINT length)
{
for(UINT i = 0; i < length; i++)
   add(b[i]);
} // checksum::add(LPBYTE, UINT)

void checksum::add(const CTime & time)
{
	time_t osBinaryTime = time.GetTime();
	add((DWORD)osBinaryTime);
}

void checksum::add(double d)
{
	char buffer[30];
	_gcvt(d, 10, buffer);
	add(CString(buffer));
}
